<?php
/**
 * The helper class file of ZenTaoPHP.
 *
 * ZenTaoPHP is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * ZenTaoPHP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with ZenTaoPHP.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @copyright   Copyright 2009-2010 青岛易软天创网络科技有限公司(www.cnezsoft.com)
 * @author      Chunsheng Wang <chunsheng@cnezsoft.com>
 * @package     ZenTaoPHP
 * @version     $Id: helper.class.php 127 2010-07-04 02:18:40Z wwccss $
 * @link        http://www.zentaoms.com
 */
/**
 * 工具类对象，存放着各种杂项的工具方法。
 *
 * @package ZenTaoPHP
 */
class helper
{
    /**
     * 为一个对象设置某一个属性，其中key可以是“father.child”的形式。
     * 
     * <code>
     * <?php
     * $lang->db->user = 'wwccss';
     * helper::setMember('lang', 'db.user', 'chunsheng.wang');
     * ?>
     * </code>
     * @param string    $objName    对象变量名。
     * @param string    $key        要设置的属性，可以是father.child的形式。
     * @param mixed     $value      要设置的值。
     * @static
     * @access public
     * @return void
     */
    static public function setMember($objName, $key, $value)
    {
        global $$objName;
        if(!is_object($$objName) or empty($key)) return false;
        $key   = str_replace('.', '->', $key);
        $value = serialize($value);
        $code  = ("\$${objName}->{$key}=unserialize(<<<EOT\n$value\nEOT\n);");
        eval($code);
    }

    /**
     * 生成某一个模块某个方法的链接。
     * 
     * 在control类中对此方法进行了封装，可以在control对象中直接调用createLink方法。
     * <code>
     * <?php
     * helper::createLink('hello', 'index', 'var1=value1&var2=value2');
     * helper::createLink('hello', 'index', array('var1' => 'value1', 'var2' => 'value2');
     * ?>
     * </code>
     * @param string    $moduleName     模块名。
     * @param string    $methodName     方法名。
     * @param mixed     $vars           要传递给method方法的各个参数，可以是数组，也可以是var1=value2&var2=value2的形式。
     * @param string    $viewType       扩展名方式。
     * @static
     * @access public
     * @return string
     */
    static public function createLink($moduleName, $methodName = 'index', $vars = '', $viewType = '')
    {
        global $app, $config;

        $link = $config->webRoot;
        if($config->requestType == 'GET')
        {
            if(strpos($_SERVER['SCRIPT_NAME'], 'index.php') === false)
            {
                $link = $_SERVER['SCRIPT_NAME'];
            }
        }

        if(empty($viewType)) $viewType = $app->getViewType();

        /* 如果传递进来的vars不是数组，尝试将其解析成数组格式。*/
        if(!is_array($vars)) parse_str($vars, $vars);
        if($config->requestType == 'PATH_INFO')
        {
            $link .= "$moduleName{$config->requestFix}$methodName";
            if($config->pathType == 'full')
            {
                foreach($vars as $key => $value) $link .= "{$config->requestFix}$key{$config->requestFix}$value";
            }
            else
            {
                foreach($vars as $value) $link .= "{$config->requestFix}$value";
            }    
            /* 如果访问的是/index/index.html，简化为/index.html。*/
            if($moduleName == $config->default->module and $methodName == $config->default->method) $link = $config->webRoot . 'index';
            $link .= '.' . $viewType;
        }
        elseif($config->requestType == 'GET')
        {
            $link .= "?{$config->moduleVar}=$moduleName&{$config->methodVar}=$methodName";
            if($viewType != 'html') $link .= "&{$config->viewVar}=" . $viewType;
            foreach($vars as $key => $value) $link .= "&$key=$value";
        }
        return $link;
    }

    /**
     * 将一个数组转成对象格式。此函数只是返回语句，需要eval。
     * 
     * <code>
     * <?php
     * $config['user'] = 'wwccss';
     * eval(helper::array2Object($config, 'configobj');
     * print_r($configobj);
     * ?>
     * </code>
     * @param array     $array          要转换的数组。
     * @param string    $objName        要转换成的对象的名字。
     * @param string    $memberPath     成员变量路径，最开始为空，从根开始。
     * @param bool      $firstRun       是否是第一次运行。
     * @static
     * @access public
     * @return void
     */
    static public function array2Object($array, $objName, $memberPath = '', $firstRun = true)
    {
        if($firstRun)
        {
            if(!is_array($array) or empty($array)) return false;
        }    
        static $code = '';
        $keys = array_keys($array);
        foreach($keys as $keyNO => $key)
        {
            $value = $array[$key];
            if(is_int($key)) $key = 'item' . $key;
            $memberID = $memberPath . '->' . $key;
            if(!is_array($value))
            {
                $value = addslashes($value);
                $code .= "\$$objName$memberID='$value';\n";
            }
            else
            {
                helper::array2object($value, $objName, $memberID, $firstRun = false);
            }
        }
        return $code;
    }

    /**
     * 包含一个文件。router.class.php和control.class.php中包含文件都通过此函数来调用，这样保证文件不会重复加载。
     * 
     * @param string    $file   要包含的文件的路径。 
     * @static
     * @access public
     * @return void
     */
    static public function import($file)
    {
        if(!file_exists($file)) return false;
        static $includedFiles = array();
        if(!isset($includedFiles[$file]))
        {
            include $file;
            $includedFiles[$file] = true;
            return true;
        }
        return false;
    }

    /**
     * 设置model文件。
     * 
     * @param   string      $moduleName     模块名字。
     * @access  private
     * @return void
     */
    static public function setModelFile($moduleName)
    {
        global $app;

        /* 设定主model文件和扩展路径，并获得所有的扩展文件。*/
        $mainModelFile = $app->getModulePath($moduleName) . 'model.php';
        $modelExtPath  = $app->getModuleExtPath($moduleName, 'model');
        $extFiles      = helper::ls($modelExtPath, '.php');

        /* 不存在扩展文件，返回主配置文件。*/
        if(empty($extFiles)) return $mainModelFile;

        /* 存在扩展文件，判断是否需要更新。*/
        $mergedModelFile = $app->getTmpRoot() . 'model' . $app->getPathFix() . $moduleName . '.php';
        $needUpdate      = false;
        $lastTime        = file_exists($mergedModelFile) ? filemtime($mergedModelFile) : 0;
        
        if(filemtime($mainModelFile) > $lastTime)
        {
            $needUpdate = true;
        }
        else
        {
            foreach($extFiles as $extFile)
            {
                if(filemtime($extFile) > $lastTime)
                {
                    $needUpdate = true;
                    break;
                }
            }
        }

        /* 如果不需要更新，则直接返回合并之后的model文件。*/
        if(!$needUpdate) return $mergedModelFile;

        if($needUpdate)
        {
            /* 加载主的model文件，并获得其方法列表。*/
            helper::import($mainModelFile);
            $modelMethods = get_class_methods($moduleName . 'model');
            foreach($modelMethods as $key => $modelMethod) $modelMethods[$key] = strtolower($modelMethod);

            /* 将主model文件读入数组。*/
            $modelLines = rtrim(file_get_contents($mainModelFile));
            $modelLines = rtrim($modelLines, '?>');
            $modelLines = rtrim($modelLines);
            $modelLines = explode("\n", $modelLines);
            $lines2Delete = array(count($modelLines) - 1);
            $lines2Append = array();

            /* 循环处理每个扩展方法文件。*/
            foreach($extFiles as $extFile)
            {
                $methodName = strtolower(basename($extFile, '.php'));
                if(in_array($methodName, $modelMethods))
                {
                    $method       = new ReflectionMethod($moduleName . 'model', $methodName);
                    $startLine    = $method->getStartLine() - 1;
                    $endLine      = $method->getEndLine() - 1;
                    $lines2Delete = array_merge($lines2Delete, range($startLine, $endLine));
                }
                $lines2Append = array_merge($lines2Append, explode("\n", trim(file_get_contents($extFile))));
            }

            /* 生成新的model文件。*/
            $lines2Append[] = '}';
            foreach($lines2Delete as $lineNO) unset($modelLines[$lineNO]);
            $modelLines = array_merge($modelLines, $lines2Append);
            if(!is_dir(dirname($mergedModelFile))) mkdir(dirname($mergedModelFile));
            $modelLines = join("\n", $modelLines);
            $modelLines = str_ireplace($moduleName . 'model', 'ext' . $moduleName . 'model', $modelLines); // 类名修改。
            file_put_contents($mergedModelFile, $modelLines);

            return $mergedModelFile;
        }
    }

    /**
     * 生成SQL查询中的IN(a,b,c)部分代码。
     * 
     * @param   misc    $ids   id列表，可以是数组，也可以是使用逗号隔开的字符串。 
     * @static
     * @access  public
     * @return  string
     */
    static public function dbIN($ids)
    {
        if(is_array($ids)) return "IN ('" . join("','", $ids) . "')";
        return "IN ('" . str_replace(',', "','", str_replace(' ', '',$ids)) . "')";
    }

    /**
     * 生成对框架安全的base64encode串。
     * 
     * @param   string  $string   要编码的字符串列表。
     * @static
     * @access  public
     * @return  string
     */
    static public function safe64Encode($string)
    {
        return strtr(base64_encode($string), '/', '.');
    }

    /**
     * 解码。
     * 
     * @param   string  $string   要解码的字符串列表。
     * @static
     * @access  public
     * @return  string
     */
    static public function safe64Decode($string)
    {
        return base64_decode(strtr($string, '.', '/'));
    }

    /**
     *  计算两个日期的差。
     * 
     * @param   date  $date1   第一个时间
     * @param   date  $date2   第二个时间
     * @access  public
     * @return  string
     */
    static public function diffDate($date1, $date2)
    {
        return round((strtotime($date1) - strtotime($date2)) / 86400, 0);
    }

    /* 获得当前的时间。*/
    static public function now()
    {
        return date(DT_DATETIME1);
    }

    /* 获得今天的日期。*/
    static public function today()
    {
        return date(DT_DATE1);
    }

    /* 判断是否0000-00-00格式的日期。*/
    static public function isZeroDate($date)
    {
        return substr($date, 0, 4) == '0000';
    }

    /* 获得某一个目录下面含有某个特征字符串的所有文件。*/
    static public function ls($dir, $pattern = '')
    {
        $files = array();
        $dir = realpath($dir);
        if(is_dir($dir))
        {
        	$dh = opendir($dir);
            if($dh) {
                while(($file = readdir($dh)) !== false) 
                {
                    if(strpos($file, $pattern) !== false) $files[] = $dir . DIRECTORY_SEPARATOR . $file;
                }
				closedir ( $dh );
			}
		}
		return $files;
	}
	
	/* 切换目录。*/
	static function cd($path = '') {
		static $cwd = '';
		if ($path) {
			$cwd = getcwd ();
			chdir ( $path );
		} else {
			chdir ( $cwd );
		}
	}
	
	/**
	 * 根据FlexGrid提交的数据生成Page对象
	 */
	static public function createPage() {
		$param = $_REQUEST;
		$page = new Page ();
		if (array_key_exists ( 'page_no', $param )) {
			$page->pageNo = $param ['page_no'];
			$page->pageSize = $param ['page_size'];
		}
		if (array_key_exists ( 'sortname', $param ) && $param ['sortname'] != 'undefined') {
			$orderBy = $param ['sortname'];
			if ($param ['sortorder'] != 'undefined')
				$orderBy .= ' ' . $param ['sortorder'];
			$page->orderBy = $orderBy;
		}
		return $page;
	}
	
	/**
	 * 根据提交的参数和model生成记录数据
	 */
	static public function D($model) {
		$q = $_REQUEST;
		$result = array ();
		$fields = $model->fields;
		foreach ( $_REQUEST as $key => $value ) {
			if (array_key_exists ( $key, $fields )) {
				$f = $fields [$key];
				// 类型转换
				if (in_array ( $f ['native_type'], array ('INT24', 'LONG' ) )) 
					$result[$key] = (int) $value;
				else
					$result[$key] = $value;
			}
		}
        return $result;
    }
    
    /**
     * 快速文件数据读取和保存 针对简单类型数据 字符串、数组
     */
	static public function F($name, $value='', $path=null) {
        global $app;
        // 取默认路径，缓存根目录/data
        if (empty($path))
        	$path = $app->getCacheRoot();
        
		static $_cache = array();
	    $filename   =   $path.$name.'.php';
	    if('' !== $value) {
	        if(is_null($value)) {
	            // 删除缓存
	            return unlink($filename);
	        }else{
	            // 缓存数据
	            $dir   =  dirname($filename);
	            // 目录不存在则创建
	            if(!is_dir($dir))  mkdir($dir);
	            return file_put_contents($filename,"<?php\nreturn ".var_export($value,true).";\n?>");
	        }
	    }
	    if(isset($_cache[$name])) return $_cache[$name];
	    // 获取缓存数据
	    if(is_file($filename)) {
	        $value   =  include $filename;
	        $_cache[$name]   =   $value;
	    }else{
	        $value  =   false;
	    }
	    return $value;
	}

    /**
	 * 创建查询条件
	 * 字段:fields=>id,title,nick,pic_url
	 * 排序  order_by =>column/asc|desc(单个排序)
	 * 前缀  $configtable =>array("name" =>"d")   (单个排序)
	 * 查询条件 
	 */
	static public function createQuery($pararms, $operator = null,$configtable=null) {
		$actionQuery = new ActionQuery ();
		$actionQuery->fields = $pararms ['fields'];
		$order_by = $pararms ['order_by'];
		if ($order_by) {
			$orderby = explode ( "/", $order_by );
			$orderfield = $orderby [0];
			if($configtable[$orderfield]){
				$orderfield = $configtable[$orderfield].".".$orderfield;
			}
			$actionQuery->addOrderbys ( $orderfield, $orderby [1] );
		}
		unset ( $pararms ['fields'] );
		unset ( $pararms ['order_by'] );
		foreach ( $pararms as $key => $value ) {
			if($configtable[$key]){
					$field = $configtable[$key].".".$key;
			}else {
				$field=$key ;
			}
			if ($operator [$key]) {
				if(preg_match("/>|<|<>/",$value)){
					$actionQuery->addCondition ( $field, $value );
				}
				else{
					if($operator[$key]=="like" && strpos($value,'%')===false){
						$value = "%".$value."%" ;
					}
					$actionQuery->addCondition ( $field, $value, $operator [$key] );
				}
			} else {
				$actionQuery->addCondition ( $field, $value );
			}
		}
		return $actionQuery;
	}

    /**
     * 将page转化为FlexGrid需要的数据
     * @param <type> $pk 主键属性名
     */
    static public function page2FlexGrid($page, $pk = "id") {
        $list = array();
        foreach ($page->result as $value)
            $list[] = array("id" => $value->$pk, "cell" => $value);
        $data = array("page" => $page->pageNo, "total" => $page->totalCount, "rows" => $list);
        return $data;
   }
     /**
     * 过滤参数(需要更好的方式)
     * $p=*, 表示过滤所有为空的$pararms,
     */
  static public function filterParams( $p=null ) {
	//$pararms = $_REQUEST;
	$pararms = array_merge($_POST, $_GET);
	unset($pararms['m']);
	unset($pararms['f']);
	unset($pararms['t']);
	unset($pararms['page_no']);;
	unset($pararms['page_size']);
	unset($pararms['sortname']);
	unset($pararms['sortorder']);
	unset($pararms['query']);
	unset($pararms['qtype']);
	unset($pararms['qop']);
	unset($pararms['XDEBUG_SESSION_START']);
	unset($pararms['KEY']);
	if($p){
		foreach ($pararms as $key=>$value){
			if($value===null||$value===""||$value=="undefined"){
				unset($pararms[$key]);
			}
			elseif(strpos($key,"confilter_")>-1){
				$array_key =  explode("_",$key) ;
				$newkey = $array_key[1].' '.$array_key[2].' '.$array_key[3] ;
				$pararms[$newkey] = $value;
				unset($pararms[$key]);
			}
		}
	}
	return $pararms;
    }
    /**
     * 时间格式化输出
     *
     * @param string $format
     * @param string $time
     * @return string
     * @author liyonghua
     */
   static public function nowTime($format ='Y-m-d H:i:s',$time='')
   {
   	if($time)
   		$datetime = $time;
   	else 
   		$datetime = time();
   		
   	return date($format,$datetime);
   }
   
   /**
    * 抛出异常
    * @param string $msg	错误描述
    * @param int $code		错误编码
	*/
	static public function throwException($msg, $code=1) {
		throw new Exception($msg, $code);   
	}
   
   static public function formattime($time){
		$str ='';
		$day  = round($time/86400+0.5)-1;
		$hour = round(($time - $day*86400)/3600+0.5)-1;
		$min  = round(($time - $day*86400-$hour*3600)/60+0.5)-1;
		$sec  = round($time - $day*86400-$hour*3600-$min*60);
		if($day>0) {
			$str=$day."天";		
		}
		if($hour>0) {
			$str.=$hour.":";		
		}
		if($min>0) {
			$str.=$min."'";
			if($day>0) {
				return $str;
			}
		} 
		else 
		{
			$str.="0'";
		}
		if($sec>0) {
			$str.=$sec."''";
		}
		else 
		{
			$str.="0''";
		}
		return $str;		
	}
	
	static public function condToString($conditions){
		$sql = ' ';
        if (is_string($conditions)){
            return $sql . $conditions;
        }
		elseif(is_array($conditions)){
			$join_char = ''; // 第一个条件前面 没有 and 连接符
			foreach ( $conditions as $field => $cond ) {
				// 支持 like / or 等操作 例如: 'name' => array('%Bob%','like')
				$op_char = '=';
				if (is_array ( $cond )) {
					$value = array_shift ( $cond );
					// if $value is array , will use "in" [] opchar
					if (is_array ( $value ))
						$value = '[' . implode ( ',', $value ) . ']';
					
					$_op_char = array_shift ( $cond );
					if (! empty ( $_op_char ) && is_string ( $_op_char ))
						$op_char = $_op_char;
					$value=  $op_char." '".$value."'";
				}elseif(strpos($cond,"null")>-1){
					if(strpos($cond,"is")<0){
						$value = " is ".$cond ;
					}else{
						$value = $cond ;
					}
				}elseif(strpos($cond,",")>-1){
					$value = " in (".$cond.")" ;
				}elseif (preg_match("/>|<|<>/",$cond)) {
					$value = $cond;
				}
				 else {
					$value = ' = '.$cond;
				}
				$sql .= "{$join_char} {$field} {$value}  ";
				$join_char = ' and ';
			}
			return $sql;
		}
	}
	/**
	 * 逐级建目录
	 *
	 * @param string $path
	 * @param int $mode
	 * @return string
	 */
	static public function createDir($path,$mode=0777) {
		if(!is_dir($path)){
			self::createDir(dirname($path));
			mkdir($path,$mode);
			@chmod($path,$mode);
		}
		return $path;
	}
	
	/**
	 * 编码转换
	 *
	 * @param unknown_type $str
	 * @param unknown_type $char
	 * @return unknown
	 */
	static public function charseticonv($str,$char='gbk') {
		if(is_array($str)) {
			foreach ($str as $k=>$v) {
				$str[$k] = self::charseticonv($v,$char);
			}
		} else {
			if($char=='gbk') {
				$str = 	iconv('utf-8','gbk',trim($str));
			} else {
				$str = 	iconv('gbk','utf-8',trim($str));
			}
		}
		return $str;
	}
	
	/**
	 * 数组去空
	 *
	 * @param array $array
	 * @return array
	 */
	static function array_remove_empty($array) {
		if(!empty($array)) {
	    	foreach ($array as $key=>$value) {
	    		if($value=='') unset($array[$key]);
	    	}
	    }
	    return $array;
	}
	/**
	 * 日志记录 
	 * 2010-12-19
	 * @author liyonghua
	 *
	 * @param unknown_type $content
	 * @param unknown_type $type
	 */
	static public function datalog($content,$type='log_') 
	{		
		global $app,$timeStart;		
		//文件名称 1--7 
		$basePath = $app->getCacheRoot().'./log/';	
		$logfile  = $basePath.$type.date('N',time()).'.php';
		if(is_file($logfile))
		{		
			//文件最后修改时间
			$lastModify = @filemtime($logfile);
			$diff = time() - $lastModify;
			//非今天文件 删除
			if($diff>86400){
				$filepath = glob($logfile.'*');
					foreach ($filepath as $unfile) {				
							@unlink($unfile);
					}	
			} elseif(@filesize($logfile) >= 2048000) {	
				//2M 分文件
				$logfilebak = $logfile.'_'.date('His').'_bak.php';
				@rename($logfile, $logfilebak);		
			}
		}
		$logstr = $content;		
		$mtime = explode(' ', microtime());
		$totaltime = @number_format(($mtime[1] + $mtime[0] - $timeStart), 4);
		
		$url=' '.$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'];      
	    $newlog = date('Y-m-d H:i:s',time()).' '.$totaltime.' '.$logstr.' '.$url;
			    
		if($fp = @fopen($logfile, 'a')) {
			@flock($fp, 2);
			fwrite($fp, "<?PHP exit;?>\t".str_replace(array('<?', '?>', "\r", "\n",), '', $newlog)."\t\n");
			fclose($fp);
		}
		unset($content,$logstr,$newlog);
	}
	
	/* 获取IP*/
	static public function getIP()
	{
		if (getenv("HTTP_CLIENT_IP"))
			$ip = getenv("HTTP_CLIENT_IP");
		else if(getenv("HTTP_X_FORWARDED_FOR"))
			$ip = getenv("HTTP_X_FORWARDED_FOR");
		else if(getenv("REMOTE_ADDR"))
			$ip = getenv("REMOTE_ADDR");
		else
			$ip = "UNKNOWN";
		return $ip;
	}
	
	/* 向一个URL地址post数据 */
	static public function init_post($post_url,$data)
	{
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $post_url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_POST, 'application/x-www-form-urlencoded');
		curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
		$output = curl_exec($ch);
		curl_close($ch);
		return $output;
	}
		
	/**
	 * 标点类型
	 *
	 * @return array
	 */
	static public function markerType()
	{
		$typearr = array(
			'0'=>'个人',
			'100'=>'自己位置',
			'300'=>'办事处',
			'400'=>'办事处区域'			
		);
		return $typearr;
	}
	
	/**
	 * 根据经纬度计算距离
	 * $lng1经度1,$lat1纬度1,$lng2经度2,$lat2纬度2
	 *  
	 * @return float 单位：KM
	 */
	static public function getdistance($lat1,$lng1,$lat2,$lng2)
	{
		$radLat1=deg2rad($lat1);//角度转为狐度
		$radLat2=deg2rad($lat2);
		$radLng1=deg2rad($lng1);
		$radLng2=deg2rad($lng2);
		$a=$radLat1-$radLat2;//两纬度之差,纬度<90
		$b=$radLng1-$radLng2;//两经度之差,经度<180
		$s=2*asin(sqrt(pow(sin($a/2),2)+cos($radLat1)*cos($radLat2)*pow(sin($b/2),2)))*6378.137;
		$s=Round($s * 10000) / 10000;
		return $s;
	}
}//end helper


	
/* 别名函数，生成对内部方法的链接。 */
function inLink($methodName = 'index', $vars = '', $viewType = '')
{
    global $app;
    return helper::createLink($app->getModuleName(), $methodName, $vars, $viewType);
}

/* 循环一个数组。*/
function cycle($items)
{
    static $i = 0;
    if(!is_array($items)) $items = explode(',', $items);
    if(!isset($items[$i])) $i = 0;
    return $items[$i++];
}
 
